/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sqlcommand;

import data.Cell;
import data.ManagerDatabase;
import data.Row;
import data.Table;
import java.util.ArrayList;

/**
 * thuc hien viec so sanh trong cac cau lenh tap hop vidu tim tat ca giao vien
 * SELECT * FROM GIAOVIEN WHERE MAGV <> ALL (SELECT MAGV WHERE PHANCONG)
 *
 * ghi chu: all -> lay tat ca cac dong trong bang <> all <=> not in truoc tu
 * khoa all phai la 1 toan tu truoc any cung phai la mot toan tu = any tuong
 * duong voi in
 *
 *
 * The ALL comparison condition is used to compare a value to a list or
 * subquery. It must be preceded by =, !=, >, <, <=, >= and followed by a list
 * or subquery. When the ALL condition is followed by a list, the optimizer
 * expands the initial condition to all elements of the list and strings them
 * together with AND operators, as shown below.
 *
 * @author Quang
 */
public class SetCondition extends JConditions {

    private String[] keyOperatorSet = {
        "IN",
        "ALL",
        "ANY",
        "SOME",};
    // danh sach cac toan tu so sanh tap hop co the co
    private String[] collectionOperatorSet = {
        "IN", "NOT IN", 
        "=ALL", "<>ALL",">ALL","<ALL","<= ALL", ">= ALL",
        "=ANY", "<>ANY"," > ANY"," < ANY","<= ANY", ">= ANY",
    };
    /*
     * dong ban dau, dua vao dieu kien se chon ra nhung dong phu hop voi yeu cau
     * vi du: SELECT * FROM GIAOVIEN WHERE MAGV IN (SELECT MAGV WHERE PHANCONG
     * PHANCONG) --> listCell: danh sach cac cell MAGV cuar cac giao vien o bang PHANCONG
     * PHANCONG --> listRow: danh sach cac row o bang GIAOVIEN
     */
    private ArrayList<Cell> listCell;
   // private ArrayList<Row> listRows;
    private ArrayList<Row> listRowsValues;// danh sach cac dong thoa dieu kien duoc nhan
    private String columnName;
    private SingleCondition singleConditon;
    private String strCondition;
    private String operatorSet;
    private ManagerDatabase manager;

    public SetCondition(String str, ArrayList<Row> rows) {
        init(str, rows);
        
    }

    private String getOperatorFormString() {
        int posOperator = strCondition.indexOf(" ");
        int posOperator2 = strCondition.indexOf(" ", posOperator+1);
        String op = strCondition.substring(posOperator, posOperator2);
        return op;
    }

    private void init(String str, ArrayList<Row> rows) {
        strCondition = Command.newStandardizeString(str);
        listCell = new ArrayList<>();
        listRowsValues = new ArrayList<>();
    }

    public SetCondition(String str, String tableName, ManagerDatabase md) {
        init(str, (ArrayList<Row> )md.getTable(tableName).getListRows());
        this.manager = md;
        
    }
    public Boolean InitValue(MyError err){
        if (getOperatorFromString(err)) {
            return false;
        }

        if (!getListCellFromSubQueryOrList(err)) {
            return false;
        }
        return true;
    }
      @Override
    public Boolean compare(Row row, MyError err) {
            // kiem tra va lay toan tu so sanh tap hop
        
        // so sanh toan bo cac dong duoc dua vao, dong nao thoa dieu kien thi lay
        
            Cell cell = row.getCell(columnName);
            if(isGetRow(cell)){                
                listRowsValues.add(row);
                return true;
            }
        

        
        return false;
    }

   
    /**
     * lay danh dach cac dong tu cau lenh dieu kien MAGV <> ALL (SELECT MAGV
     * WHERE PHANCONG)
     *
     * @return DANH SCH
     */
    private boolean getListCellFromSubQueryOrList(MyError err) {

        // lay cau lenh sql tu chuoi dieu kien ban dau
        int pos = strCondition.indexOf("(");
        if (strCondition.indexOf(")") == -1) {
            err.setError("Error!! Thieu dau ')'");
            return false;
        }
        String sql = strCondition.substring(pos + 1, strCondition.length() - 1);
        if (haveSubQuery(sql)) { // la cau truy van con
            //this.setListCell(getCellFromSubQuery(sql));
            this.listCell = getCellFromSubQuery(sql,err);
            if(listCell == null){
                return false;
            }
        } else { // la mot tap hop
            this.setListCell(getCellFromList(sql,err));
        }
        
        
        return true;
    }

    // kiem tra cac dong phu hop
    private Boolean isGetRow(Cell cell) {
        
        int index=-1;
        for(int i=0; i<collectionOperatorSet.length; i++){
            if(operatorSet.equals(collectionOperatorSet[i])){
                index = i;
                break;
            }
        }
        
//          "IN", "NOT IN", 
//        "= ALL", "<> ALL"," > ALL"," < ALL","<= ALL", ">= ALL",
//        "= ANY", "<> ANY"," > ANY"," < ANY","<= ANY", ">= ANY",
        switch (index) {
            case 0: { // IN               
                return inOperator(cell);
            }
            case 1: {//NOT IN
                return !inOperator(cell);
            }
                // 
            case 2: 
            case 3: 
            case 4: 
            case 5: 
            case 6:
            case 7: 
                return allOperator(cell);
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
                return anyOperator(cell);
               
            
        }

        return false;
    }

   
    private boolean haveSubQuery(String sql) {
        if (Command.indexOfString(sql, "SELECT") == 0) {
            return true;
        }
        return false;
    }

    private ArrayList<Cell> getCellFromSubQuery(String sql, MyError err) {
        Select select = new Select(sql, this.manager);
        
        ArrayList<Row> rows = select.excute(err);
        if(rows == null){
            return null;
        }
        ArrayList<Cell> cells = new ArrayList<>();
        for (int i = 0; i < rows.size(); i++) {
            for (int j = 0; j < rows.get(i).getListCell().size(); j++) {
                if (rows.get(i).getListCell().get(j).getName().equals(columnName)) {
                    cells.add(rows.get(i).getListCell().get(j));
                }

            }
        }
        return cells;
    }
/**
 * lay danh sach cac cot tu tap hop
 * vidu MAGV IN ('GV001','GV002')
 * @param listString
 * @return 
 */
    private ArrayList<Cell> getCellFromList(String listString, MyError err) {
        ArrayList<Cell> cells = new ArrayList<>();
        ArrayList<String> strs = TachChuoi(listString, err);
        for (int i = 0; i < strs.size(); i++) {
            cells.add(new Cell(strs.get(i), 0, columnName));
        }
        return cells;


    }
     /**
     * tach chuoi dang 'abc',12,'def'
     * thanh tung chuoi con abc, def
     * @param str
     * @return danh sach chuoi
     */
    private ArrayList<String> TachChuoi(String str, MyError error) {
        // kiem tra dau nhay don va ngoac don
        StringBuffer colsName = new StringBuffer(str);
        ArrayList<String> arr = new ArrayList<String>();
        while (true) {
            int posComma = colsName.indexOf(",");
            if (posComma != -1) {
                String col;
                if(colsName.charAt(0) =='\'')
                    col = colsName.substring(1, posComma - 1);
                else
                    col = colsName.substring(0, posComma );
                if (col.indexOf(" ") != -1) {
                    error.setError("Error! Ten  cot khong hop le");
                    return null;
                } else {
                    arr.add(col);
                    colsName.delete(0, posComma + 2);
                }
            } else {
                if (colsName.indexOf(" ") != -1) {
                    error.setError("Error! Ten cot khong hop le");
                    return null;
                } else {
                    if (colsName.charAt(0) == '\'') {
                        colsName.deleteCharAt(0);
                    }
                    if (colsName.charAt(colsName.length() - 1) == '\'') {
                        colsName.deleteCharAt(colsName.length() - 1);
                    }
                    arr.add(colsName.toString());
                    break;
                }
            }
        }
        return arr;
    }

    private boolean getOperatorFromString(MyError err) {

        //begin
        try{
        int posOperator = -1;
        for (int i = 0; i < keyOperatorSet.length; i++) {
            posOperator = Command.indexOfString(getStrCondition(), keyOperatorSet[i]);
            if (posOperator != -1) {
                operatorSet = keyOperatorSet[i];
                if( "SOME".equals(operatorSet))
                    operatorSet = "ANY";
                break;
            }
        }
        if (getOperatorSet() == null) {
            err.setError("Error!!! Khong co tu khoa so sanh tap hop");
            return true;
        }
        // kiem tra xem co ton tai mot so tien to phia truoc toan tu khong
        if ("IN".equals(getOperatorSet())) {
            // neu toan tu la in
            int posNot = Command.indexOfString(getStrCondition(), "NOT");
            if (posNot == posOperator - 4) {
                operatorSet = "NOT IN";
                posOperator = posNot;
            }
        } else {
            int pos = -1;
            for (int i = 0; i < this.keyWordOperator.length; i++) {
                pos = Command.indexOfString(getStrCondition(), keyWordOperator[i]);
                if (pos != -1 && pos + keyWordOperator[i].length() + 1 == posOperator) {
                    operatorSet = keyWordOperator[i] + getOperatorSet();
                    posOperator = pos;
                    break;
                }
            }
            if (pos == -1) {
                err.setError("Error!! Thieu toan tu so sanh truoc toan tu tap hop");
                return true;
            }
        }

        //lay ten cot
        // lay danh sach cac cot
        StringBuffer sbuff = new StringBuffer(this.strCondition);
        int posSelect = Command.indexOfString(sbuff, "SELECT");
        String s1 = this.strCondition.substring(0, posOperator);
        if (s1 == " ") {
            err.setError("Error!!! Ten bang khong hop le");
            return true;
        }

        StringBuffer cols = new StringBuffer(s1);
        if (cols.charAt(0) == '*') {
            err.setError("Error!!! Ten bang khong hop le");
            return true;
        } else {
            int pos = cols.indexOf(",");
            // co dau ","
            if (pos != -1) {
                err.setError("Error!! Chi duoc lua chon 1 bang");
                return false;
            }
            columnName = Command.newStandardizeString(cols.toString());

        }
        return false;
        }catch(Exception e){
            System.out.println(e.toString());
            return false;
        }
    }

    /**
     * lay danh sach cac dong thoa dieu kien
     *
     * @return
     */
    public ArrayList<Row> excute() {
        ArrayList<Row> rows = new ArrayList<>();
        return rows;
    }

  

   

    /**
     * @return the columnName
     */
    public String getColumnName() {
        return columnName;
    }

    /**
     * @return the singleConditon
     */
    public SingleCondition getSingleConditon() {
        return singleConditon;
    }

    /**
     * @return the strCondition
     */
    public String getStrCondition() {
        return strCondition;
    }

    /**
     * @return the operatorSet
     */
    public String getOperatorSet() {
        return operatorSet;
    }

    /**
     * @return the listCell
     */
    public ArrayList<Cell> getListCell() {
        return listCell;
    }

    /**
     * @param listCell the listCell to set
     */
    public void setListCell(ArrayList<Cell> listCell) {
        this.listCell = listCell;
    }

    private boolean inOperator(Cell cell) {
        for (int j = 0; j < listCell.size(); j++) {
            if (cell.getData().equals(listCell.get(j).getData())) {
                return true;
            }
        }
        return false;
    }
    private Boolean allOperator(Cell cell) {
        String op = getOperatorFormString();
        MyError err = new MyError();
        for(int i=0; i<listCell.size(); i++){
            SingleCondition sc = new SingleCondition();
            sc.setConndition(cell.getData(),listCell.get(i).getData(),op);
            if(!sc.compare(err))
                return false;
        }
        return true;
    }

    private Boolean anyOperator(Cell cell) {
        String op = getOperatorFormString();
        MyError err = new MyError();
        for(int i=0; i<listCell.size(); i++){
            SingleCondition sc = new SingleCondition();
            sc.setConndition(cell.getData(),listCell.get(i).getData(),op);
            if(sc.compare(err))
                return true;
        }
        return false;
        
    }
}
